package com.ibr.ticketmanagement.app.util;

import android.util.Base64;
import android.util.Log;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
 * Created by girishn on 5/29/2014.
 */
public class WsseToken {

    public static final String HEADER_AUTHORIZATION = "Authorization";
    public static final String HEADER_WSSE = "X-WSSE";

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    //in our case, User is an entity (just a POJO) persisted into sqlite database
    private String username;
    private String password;
    private String nonce;
    private String createdAt;
    private String digest;
    private String salt;

    public WsseToken(String username, String password, String salt) {
        //we need the user object because we need his username
        this.username = username;
        this.salt = salt;
        this.password = hashPassword(password);
        this.createdAt = generateTimestamp();
        this.nonce = generateNonce();
        this.digest = generateDigest();
    }

    public static String bytesToHex(byte[] bytes) {
        final char[] hexArray = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        char[] hexChars = new char[bytes.length * 2];
        int v;
        for (int j = 0; j < bytes.length; j++) {
            v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    private String hashPassword(String clearPassword) {
        String hash = "";
        try {
            //Log.d("AuthProvider", "start hashing password...");
            String salted = null;
            if (salt == null || "".equals(salt)) {
                salted = clearPassword;
            } else {
                salted = clearPassword + "{" + salt + "}";
            }
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte sha[] = md.digest(salted.getBytes());
            for (int i = 1; i < 5000; i++) {
                byte c[] = new byte[sha.length + salted.getBytes().length];
                System.arraycopy(sha, 0, c, 0, sha.length);
                System.arraycopy(salted.getBytes(), 0, c, sha.length, salted.getBytes().length);
                sha = md.digest(c);
            }
            hash = new String(Base64.encode(sha, Base64.NO_WRAP));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            //do something with this exception
        }
        //Log.d("AuthProvider", "hashing password is done!");
        return hash;
//        return clearPassword;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    private String generateNonce() {
        SecureRandom random = new SecureRandom();
        byte seed[] = random.generateSeed(10);
        return bytesToHex(seed);
    }

    private String generateTimestamp() {
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
        return sdf.format(new Date(System.currentTimeMillis()));
    }

    private String generateDigest() {
        String digest = null;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            StringBuilder sb = new StringBuilder();
            sb.append(this.nonce);
            sb.append(this.createdAt);
            sb.append(this.getPassword());
            byte sha[] = md.digest(sb.toString().getBytes());
            digest = Base64.encodeToString(sha, Base64.NO_WRAP);
            Log.d("digest", digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return digest;
    }

    public String getWsseHeader() {
        StringBuilder header = new StringBuilder();
        header.append("UsernameToken Username=\"");
        header.append(this.getUsername());
        header.append("\", PasswordDigest=\"");
        header.append(this.digest);
        header.append("\", Nonce=\"");
        header.append(Base64.encodeToString(this.nonce.getBytes(), Base64.NO_WRAP));
        header.append("\", Created=\"");
        header.append(this.createdAt);
        header.append("\"");
        Log.d("header", header.toString());
        return header.toString();
    }

    public String getAuthorizationHeader() {
        return "WSSE profile=\"UsernameToken\"";
    }
}
